#include "ubvm_wrapper.h"
#include "DIVA_Manager.h"
#include <sstream>
#include "xParameterPack.h"
#include "vmLibrary.h"

ubvm_wrapper::ubvm_wrapper( xParameterPack xpp ):DIVA_VM(xpp){

	assert(xpp.no==vmLibrary::instance().get_vm_default_input_parameters().size()+1);

	int vms_port = vmLibrary::instance().get_vm_default_input_parameters().size();
	_child_vms = xpp.paras[vms_port].val_vms ; // set up the private attributes

	init_default_parameters();
}	

void ubvm_wrapper::load_3Dresources() {

	vector<DIVA_VM*>::iterator itr;
	for(itr=_child_vms.begin();itr!=_child_vms.end();itr++){
		
		Ogre::Vector3 pos=(*itr)->getPosition(); 
		Ogre::SceneNode *parent = (*itr)->getParentSceneNode() ;
		Ogre::SceneNode *s = (*itr)->getSceneNode();
		parent->removeChild(s);
		_SceneNode->addChild(s);
		(*itr)->setParentSceneNode(_SceneNode);
		//s->setInheritScale(false);
		(*itr)->setPosition(pos);
	}
}
void ubvm_wrapper::set_default_values() {
	_vm_rx_val = 0 ;
	_vm_ry_val = 0 ;
	_vm_rz_val = 0 ;

	Ogre::Vector3 sz = this->getActualSize();
	_vm_init_sizex = sz.x ;
	_vm_init_sizey = sz.y ;
	_vm_init_sizez = sz.z ;

	_vm_sizex_val = sz.x ;
	_vm_sizey_val = sz.y ;
	_vm_sizez_val = sz.z ;

	_vm_sizexscale_val = 1.0 ;
	_vm_sizeyscale_val = 1.0 ;
	_vm_sizezscale_val = 1.0 ;

	_vm_r_val = 0.3;  // white color but with transparency 0.1
	_vm_g_val = 0.3;
	_vm_b_val = 0.3;
	_vm_transparency_val = 1.0 ;

	_vm_yaw_val = 0 ;
	_vm_pitch_val = 0 ;
	_vm_roll_val = 0 ;

}
void ubvm_wrapper::reg_event_entity() {

	// register the relation of the entity and vm in diva manager
	// When this entity is clicked, mouse/keyboard VM will be passed to this VM
	// By default it can be only one entity representing this VM
}
void ubvm_wrapper::init_private_attrs_started() {
	
}
void ubvm_wrapper::init_color_and_transparency() {

	if (_prohibit_defaults[SKIP_COLOR] == true)
		return ;

	assert(_vm_r_val > 0.0 && _vm_g_val > 0.0 && _vm_b_val > 0.0) ;
	// the three variables should be set correctly in set_default_values
	
	//if (_para_onoff[RGB] || _para_onoff[RGB+1] || _para_onoff[RGB+2] || _para_onoff[TRANS] ) {
	if(_vm_r) _vm_r_val = *_vm_r ;
	if(_vm_g) _vm_g_val = *_vm_g ;
	if(_vm_b) _vm_b_val = *_vm_b ;

	if(_vm_transparency)  _vm_transparency_val = (*_vm_transparency);

	assert((_vm_r_val) >= 0.0 && (_vm_r_val) <= 1.0);
	assert((_vm_g_val) >= 0.0 && (_vm_g_val) <= 1.0);
	assert((_vm_b_val) >= 0.0 && (_vm_b_val) <= 1.0);
	assert((_vm_transparency_val) >= 0.0 && (_vm_transparency_val) <= 1.0);
	//}

	// in the following, we dump each child node 
	// for each child node, we retrieve the entity object of the child node
	// at last, we set the color according to the value 
	Ogre::Node::ChildNodeIterator iterator = _SceneNode->getChildIterator();
	while(iterator.hasMoreElements()) {
        Ogre::SceneNode* n = dynamic_cast<Ogre::SceneNode*>(iterator.getNext());
		if(n) {
			Ogre::SceneNode::ObjectIterator object_it = n->getAttachedObjectIterator();
			Ogre::MovableObject *m;
			while(object_it.hasMoreElements()) {
				 m = object_it.getNext();
				 if (m->getMovableType() == "Entity") {
					Ogre::Entity* ent  = dynamic_cast<Ogre::Entity*>(m) ;
					if (!ent) assert(false);
					VL_setEntityColor(ent,Ogre::Vector4(_vm_r_val, _vm_g_val, _vm_b_val, _vm_transparency_val));
				 }
			}
			
		}
	}

}
void ubvm_wrapper::update_color_and_transparency() {

	init_color_and_transparency();
}
void ubvm_wrapper::VMSetVisible(bool vis) {
	if (_visible != vis) {
		  _visible = vis ;
         _SceneNode->setVisible(vis);
	}
	vector<DIVA_VM*>::iterator itr;
	for(itr=_child_vms.begin();itr!=_child_vms.end();itr++){
		DIVA_VM *vm = (*itr);
		vm->VMSetVisible(vis);
	}
		
}
void ubvm_wrapper::VMDragged(Ogre::Real screenx,Ogre::Real screeny, Ogre::Real absx,Ogre::Real absy,Ogre::Real absz) {
	// a container contains a lot of child VMs.
	// (x,y,z) are the place which is clicked but it is not necessary the center of the container VM
	// when the first time a VM is picked, we save the position of the container scene node

	if (_freshclick) {
		_dist = Ogre::Vector3(absx,absy,absz) - _center ;
		_freshclick = false;
	}
	if (isDraggedOn()) {
		Ogre::Vector3 newcenter = Ogre::Vector3(absx,absy,absz) - _dist ;
		this->setPosition(newcenter);
	}
}
void ubvm_wrapper::VMPicked(Ogre::Real x, Ogre::Real y, Ogre::Real z) {
	_center  = getPosition();
	_freshclick = true ;

	DIVA_VM::VMPicked(x,y,z); // called the default implementation to show the clickmsg
	//int current_hit = 0;
	//current_hit = VL_propagateMouseEvent(_child_vms,Vector3(x,y,z));
}
void ubvm_wrapper::VMValueUpdated() {

	DIVA_VM::VMValueUpdated();
}
bool ubvm_wrapper::isSubComponent(DIVA_VM *vm) {
	
	vector<DIVA_VM*>::iterator itr;
	for(itr=_child_vms.begin();itr!=_child_vms.end();itr++){
		DIVA_VM *kid=(*itr);
		if (kid->isSubComponent(vm)) return true ;
	}
	return false ;
}
//-----------------------------------------------------------------------
void ubvm_wrapper::scaleBodyToAbsSize(Ogre::Vector3 v){
	setBodyScale(Ogre::Vector3(v.x/_vm_init_sizex,
		                 v.y/_vm_init_sizey,
						 v.z/_vm_init_sizez));
}
void ubvm_wrapper::setBodyScale(Ogre::Vector3 scale) {
	_SceneNode->setScale(scale);
}
bool ubvm_wrapper::isBodyScaleWrtSceneNode() { return true ; }

Ogre::Vector3 ubvm_wrapper::getOriginalBodySize() {
	return Ogre::Vector3(_vm_init_sizex, _vm_init_sizey, _vm_init_sizez) ;
}

Ogre::Vector3 ubvm_wrapper::getActualSize() {
	return getBoundingBoxSize();
}
Ogre::Vector3 ubvm_wrapper::getBodyScale() {
	return _SceneNode->getScale();
}

Ogre::Vector3 ubvm_wrapper::getBoundingBoxSize(){
	
	Ogre::Vector3 max=Ogre::Vector3(0,0,0);
	Ogre::Vector3 min=Ogre::Vector3(0,0,0);

	vector<DIVA_VM*>::iterator itr;
	for(itr=_child_vms.begin();itr!=_child_vms.end();itr++){
		
		Ogre::Vector3 pos=(*itr)->getPosition();
		Ogre::Vector3 size=(*itr)->getActualSize();

		if (pos.x+size.x/2 >= max.x) max.x = pos.x+size.x/2;
		if (pos.x-size.x/2 <= min.x) min.x = pos.x-size.x/2;
		if (pos.y+size.y/2 >= max.y) max.y = pos.y+size.y/2;
		if (pos.y-size.y/2 <= min.y) min.y = pos.y-size.y/2;
		if (pos.z+size.z/2 >= max.z) max.z = pos.z+size.z/2;  
		if (pos.z-size.z/2 <= min.z) min.z = pos.z-size.z/2;

		(*itr)->setPosition(pos);
	}

	Ogre::Vector3 bb;
	bb.x=max.x-min.x; assert(bb.x>0);
	bb.y=max.y-min.y; assert(bb.y>0);
	bb.z=max.z-min.z; assert(bb.z>0);
	
	//this->scaleBodyToAbsSize(container_size*2.2);
	return bb ;
}
